package com.lt.test.provider.dao;

import com.lt.test.common.util.StringUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BaseDaoSupport{
	
	private static Logger log = LoggerFactory.getLogger(BaseDaoSupport.class);
	@Autowired
	private SqlSessionTemplate sqlSessionTemplate;
	
	@Autowired
	private JdbcTemplate jdbcTemplate;

	protected Map<String, String> labels = new ConcurrentHashMap<String,String>();
	
	public SqlSessionTemplate getSqlSession(){
		return sqlSessionTemplate;
	}
	
 
	/**
	 * 描述：获取运行结果集对应的Map 
	 * @param id SQL映射 ID
	 * @param  parameter Object对象
	 * @return String
	 */
	public List<ResultMapping> getResultMap(String statementName){ 
		Configuration configuration = getSqlSession().getConfiguration(); 
		MappedStatement mappedStatement = configuration.getMappedStatement(statementName); 
		String resultMapId = mappedStatement.getResultMaps().size() > 0 ? mappedStatement.getResultMaps().get(0).getId() : null;
		SqlSessionFactory sqlSessionFactory = getSqlSession().getSqlSessionFactory();  
		List<ResultMapping> mapping = new ArrayList<ResultMapping>(); 
		if( resultMapId != null){
			ResultMap resultMap = sqlSessionFactory.getConfiguration().getResultMap(resultMapId);
			mapping = resultMap.getResultMappings(); 
		}
		return mapping;   
	}
	
	/**
	 * 查询返回列表
	 * @param statementName
	 * @param param
	 * @return
	 */
	public List queryForList(String statementName,Object parameter){
		Class clazz = parameter.getClass();
		if(clazz.isAssignableFrom(HashMap.class) || clazz.isAssignableFrom(Map.class)) 
			wrapSearchParameter(statementName, (Map)parameter);
		return getSqlSession().selectList(statementName, parameter);
	}
	
	public <T> T queryForSingle(String statementName,Object parameter){ 
		Class clazz = parameter.getClass();
		if(clazz.isAssignableFrom(HashMap.class) || clazz.isAssignableFrom(Map.class)) 
			wrapSearchParameter(statementName, (Map)parameter);
		return (T) getSqlSession().selectOne(statementName, parameter);
	}
	
	/**
	 * 插入记录
	 * @param statementName
	 * @return
	 */
	public int insert(String statementName){ 
		return insert(statementName);
	}
	
	/**
	 * 插入记录
	 * @param statementName
	 * @param param
	 * @return
	 */
	public int insert(String statementName, Object parameter){ 
		int rowCount = this.getSqlSession().insert(statementName,parameter); 
		return rowCount;
	}

	/**
	 * 更新记录
	 * @param statementName
	 * @return
	 */
	public int update(String statementName){ 
		return update(statementName);
	}
	
	/**
	 * 插入记录
	 * @param statementName
	 * @param param
	 * @return
	 */
	public int update(String statementName, Object parameter){  
		int rowCount = this.getSqlSession().update(statementName,parameter); 
		return rowCount;
	}
	
	/**
	 * 删除记录
	 * @param statementName
	 * @return
	 */
	public int delete(String statementName){ 
		return delete(statementName);
	}
	
	/**
	 * 删除记录
	 * @param statementName
	 * @param parameter
	 * @return
	 */
	public int delete(String statementName, Object parameter){ 
		int rowCount = this.getSqlSession().delete(statementName,parameter); 
		return rowCount;
	}
	
	
	
	/**
	 * 重新封装查询列表,对searchType='complex'的集合searchExpr重新封装,将property映射成column
	 * @param list
	 * @return
	 */
	private void wrapSearchParameter(String statementName,Map parameter){
		if(parameter.get("searchType") != null && parameter.get("searchType").equals("complex")){ 
			List<Map> values = (List<Map>)parameter.get("searchExpr");
			log.info("-->Mybatis 重新封装查询  searchType = complex" + " data=" + parameter);
			for(Map row : values)   
				row.put("column", getColumn(statementName,row.get("property").toString()));  
			parameter.put("searchExpr", values);
			log.info("-->Mybatis 重新封装查询  searchType = complex" + " result=" + parameter);
		} 
	}
	
	/**
	 * 根据属性获取数据列名
	 * @param statementName
	 * @param property
	 * @return
	 */
	private String getColumn(String statementName,String property){
		String result = property;
		List<ResultMapping> resultMappingList = getResultMap(statementName);
		for(ResultMapping rm : resultMappingList)
			if(rm.getProperty().equals(property))
				return rm.getColumn();
		return result; 
	}
	
	@SuppressWarnings(value={"unchecked","rawtypes"})
	public Map<String,Object> query(String sql, Object[] args){
		return jdbcTemplate.query(sql, args,new ResultSetExtractor<Map>() {

			@Override
			public Map extractData(ResultSet rs) throws SQLException, DataAccessException {
				// TODO Auto-generated method stub
				Map<String,Object> obj = null;
				if(rs.next()){
					obj = new HashMap<String,Object>();
					ResultSetMetaData meta = rs.getMetaData();
					for (int i = 0; i < meta.getColumnCount(); i++) {
						 String columnName =meta.getColumnName(i+1); 
				            String value = rs.getString(columnName); 
				            obj.put(formatColumnLabel(columnName), value); 
					}
				}
				return obj;
			}
		});
	}
	
	@SuppressWarnings(value={"unchecked","rawtypes"})
	public Map<String, Object> queryMap(String sql,Object[] args){
		return jdbcTemplate.query(sql,args,new ResultSetExtractor<Map>(){

			@Override
			public Map extractData(ResultSet rs) throws SQLException, DataAccessException {
				Map<String, Object> obj = null;
				if(rs.next()){
					obj = new HashMap<String,Object>();
					ResultSetMetaData meta = rs.getMetaData();
					for (int i = 0; i < meta.getColumnCount(); i++) {
						 String columnName =meta.getColumnName(i+1); 
				            String value = rs.getString(columnName); 
				            obj.put(columnName, value); 
					}
				}
				return obj;
			}
			
		});
	}
	
	@SuppressWarnings(value={"unchecked","rawtypes"})
	public List<Map<String,Object>> queryAsArray(String sql, Object[] args) {
		return jdbcTemplate.query(sql, args,new ResultSetExtractor<List>() {

			@Override
			public List extractData(ResultSet rs) throws SQLException, DataAccessException {
				// TODO Auto-generated method stub
				List<Map<String,Object>> array = new ArrayList<Map<String,Object>>();
				while(rs.next()){
					Map<String,Object> obj = new HashMap<String,Object>();
					ResultSetMetaData meta = rs.getMetaData();
					for (int i = 0; i < meta.getColumnCount(); i++) {
						 String columnName =meta.getColumnName(i+1); 
				            String value = rs.getString(columnName); 
				            obj.put(formatColumnLabel(columnName), value); 
					}
					array.add(obj);
				}
				return array;
			}
		});
	}
	@SuppressWarnings(value={"unchecked","rawtypes"})
	public List<Map<String,Object>> queryOrgAsArray(String sql, Object[] args) {
		return jdbcTemplate.queryForList(sql,args);
	}	
	public void excuteSql(String sql, Object[] args){
		jdbcTemplate.update(sql, args);
	}
	 
	public void batchInsert(String sql,final List<Map> list){
		
		
		jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
			
			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				// TODO Auto-generated method stub
				Map data = list.get(i);
				int j =0;
				for(Object key : data.keySet()){
					ps.setObject(++j, data.get(key));
				}
			}
			
			@Override
			public int getBatchSize() {
				// TODO Auto-generated method stub
				return list.size();
			}
		});
	}
	
	private String formatColumnLabel(String label) {
	    if (StringUtils.isNullOrEmpty(label)) {
	      return label;
	    }
	    String string = (String)this.labels.get(label);
	    if (string != null) {
	      return string;
	    }
	    StringBuffer sb = new StringBuffer();
	    boolean line = false;
	    for (char ch : label.toLowerCase().toCharArray())
	      if (ch == '_') {
	        line = true;
	      }
	      else if (line) {
	        line = false;
	        sb.append((char)((ch >= 'a') && (ch <= 'z') ? ch - 'a' + 65 : ch));
	      }
	      else
	      {
	        sb.append(ch);
	      }
	    string = sb.toString();
	    this.labels.put(label, string);

	    return string;
	  }
}
